import {AxiosResponse, InternalAxiosRequestConfig, AxiosInstance, AxiosRequestConfig} from 'axios'
import type {AxiosConfig, IResponse} from "@/typings/axios";
import {ExclamationCircleFilled} from "@ant-design/icons";
import {message, notification, modal} from '@/hooks/modules/useMessage';
import {saveAs} from 'file-saver'
import {antdSpin} from "antd-spin";
import {blobValidate, errorCode} from "@/utils";
import {getCookieToken} from "@/utils/auth";
import {useUserStore} from "@/store/user";
import axios from "axios";

const useRequest: AxiosInstance = axios.create({
    baseURL: import.meta.env.VITE_APP_BASE_URL,
    timeout: 100000
})

useRequest.interceptors.request.use((request: InternalAxiosRequestConfig) => {
    request.headers['Authorization'] = 'Bearer ' + getCookieToken()
    return request
}, error => {
    Promise.reject(error)
})

useRequest.interceptors.response.use((res: AxiosResponse) => {
        const code = res.data.code || 200;
        const msg = errorCode[code] || res.data.msg || res.data.message || errorCode['default']
        if (res.request.responseType === 'blob' || res.request.responseType === 'arraybuffer') return res.data
        if (code === 401 || code === 403) {
            message.warning('登录状态已过期，请重新登录。', 3)
            modal.confirm({
                title: '温馨提示 🧡',
                icon: <ExclamationCircleFilled/>,
                content: '登录状态已过期，您可以继续留在该页面，或者重新登录。',
                cancelText: '取消',
                okText: '重新登录',
                onOk: () => {
                    const {signOut} = useUserStore.getState()
                    signOut()
                    window.$navigate('/login', {replace: true})
                }
            });
            return Promise.reject('无效的会话，或者会话已过期，请重新登录。')
        } else if (code === 500) {
            message.error(msg, 3)
            return Promise.reject(new Error(msg))
        } else if (code === 601) {
            message.warning(msg, 3)
            return Promise.reject(new Error(msg))
        } else if (code !== 200) {
            notification.error({message: msg})
            return Promise.reject('error')
        } else {
            return Promise.resolve(res.data)
        }

    },
    error => {
        let {message: msg} = error;
        if (msg == "Network Error") {
            msg = "后端接口连接异常";
        } else if (msg.includes("timeout")) {
            msg = "系统接口请求超时";
        } else if (msg.includes("Request failed with status code")) {
            msg = "系统接口" + msg.substring(msg.length - 3) + "异常";
        }
        message.error(msg, 5)
        return Promise.reject(error)
    })


class Request {
    post = <T = any>(url: AxiosConfig["url"], data: AxiosConfig["data"] = {}, _config: AxiosRequestConfig = {}) => {
        return useRequest.post(url, data, _config) as Promise<IResponse<T>>
    }
    put = <T = any>(url: AxiosConfig["url"], data: AxiosConfig["data"] = {}, _config: AxiosRequestConfig = {}) => {
        return useRequest.put(url, data, _config) as Promise<IResponse<T>>
    }
    get = <T = any>(url: AxiosConfig["url"], params: AxiosConfig["params"] = {}, _config: AxiosRequestConfig = {}) => {
        return useRequest.get(url, {params, ..._config}) as Promise<IResponse<T>>
    }

    delete = <T = any>(url: AxiosConfig["url"], params: AxiosConfig["params"] = {}, _config: AxiosRequestConfig = {}) => {
        return useRequest.delete(url, {params, ..._config}) as Promise<IResponse<T>>
    }

    exportFile = async (option: {
        method?: AxiosConfig["method"],
        url: AxiosConfig["url"],
        params?: AxiosConfig["params"],
        filename: string,
        _config?: AxiosConfig
    }) => {
        const {method = 'get', url, params = {}, filename, _config} = option
        const loadingInstance = antdSpin.service({
            fullscreen: true,
            background: 'rgba(0, 0, 0, 0.2)',
            spinProps: {size: "large"}
        });
        try {
            const resp = await useRequest({
                method,
                url,
                ...(method === 'get' ? {params} : {data: params}),
                ...{
                    responseType: 'blob',
                    ..._config
                }
            }) as unknown as Blob

            const isBlob: boolean = blobValidate(resp);
            if (isBlob) {
                const blob: Blob = new Blob([resp]);
                saveAs(blob, filename);
            } else {
                const resText = await resp.text();
                const rspObj = JSON.parse(resText);
                const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default'];
                message.error(errMsg, 3);
            }
            loadingInstance.close();
        } catch {
            message.error('导出文件失败！', 3);
            loadingInstance.close();
        }
    }

}

export default new Request()
